package com.bestcem.xm.award.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson.JSON;
import com.bestcem.bp.grpc.v1.base.Code;
import com.bestcem.bp.pay.grpc.v1.services.GetLuckyMoneyStatusRequest;
import com.bestcem.bp.pay.grpc.v1.services.GetLuckyMoneyStatusResponse;
import com.bestcem.bp.pay.grpc.v1.services.LuckyMoneyInfo;
import com.bestcem.xm.award.constant.Constants;
import com.bestcem.xm.award.constant.RedisKeyConstant;
import com.bestcem.xm.award.dao.AwardAwardDao;
import com.bestcem.xm.award.dao.AwardHistoryDao;
import com.bestcem.xm.award.dao.AwardRedPacketStatsDao;
import com.bestcem.xm.award.dao.AwardWinDao;
import com.bestcem.xm.award.entity.pojo.AwardAwardDO;
import com.bestcem.xm.award.enums.AwardSettlementEnum;
import com.bestcem.xm.award.enums.AwardStatusEnum;
import com.bestcem.xm.award.enums.RedPacketStatusEnum;
import com.bestcem.xm.award.grpc.client.ActivityGrpcService;
import com.bestcem.xm.award.grpc.client.AwardBaseQdesGrpcService;
import com.bestcem.xm.award.grpc.client.AwardBaseUserGrpcService;
import com.bestcem.xm.award.grpc.client.ProjectGrpcService;
import com.bestcem.xm.award.mq.dto.*;
import com.bestcem.xm.award.service.AwardAwardService;
import com.bestcem.xm.award.service.AwardMqHandler;
import com.bestcem.xm.award.service.DrawCommonService;
import com.bestcem.xm.award.service.dto.ChangeActivityStatusBodyDTO;
import com.bestcem.xm.award.util.DrawUtil;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.componet.sms.SmsService;
import com.bestcem.xm.qdes.grpc.v1.services.GetProjectRequest;
import com.bestcem.xm.qdes.grpc.v1.services.ProjectResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import zhongyan.xm.base.v1.Base;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;

import static com.bestcem.xm.award.constant.Constants.*;

/**
 * @author xa.zhang <xa.zhang@idiaoyan.com>
 * @version v1.0
 * @date 2021/7/19 17:34
 * @desc
 */
@Slf4j
@Service
public class AwardMqHandlerImpl implements AwardMqHandler {

    @Resource
    private AwardDispatcher awardDispatcher;

    @Resource
    private AwardAwardDao awardAwardDao;

    @Resource(name = "winDaoMysql")
    private AwardWinDao awardWinDao;

    @Resource
    private ActivityGrpcService activityGrpcService;

    @Resource
    private ProjectGrpcService projectGrpcService;

    @Resource
    private AwardHistoryDao awardHistoryDao;

    @Resource
    private DrawCommonService drawCommonService;

    @Resource
    private AwardRedPacketStatsDao awardRedPacketStatsDao;

    @Resource
    private AwardBaseQdesGrpcService qdesGrpcService;

    @Resource
    private AwardBaseUserGrpcService userGrpcService;

    //@Resource
    //private SmsGrpcService smsGrpcService;

    @Resource
    private SmsService smsService;

    @Resource
    private RedisService redisService;

    /**
     * 根据temp_id清除AWARD_TEMP表
     *
     * @param tempCleanDTO 消息参数
     * @return 处理结果 true: 成功 false: 失败
     */
    @Override
    public boolean cleanAwardTempByTempId(TempCleanDTO tempCleanDTO) {
        return false;
    }

    /**
     * 启动抽奖奖励
     *
     * @param drawAwardStartDTO 消息参数
     * @return 处理结果 true: 成功 false: 失败
     */
    @Override
    public boolean startDrawAward(DrawAwardStartDTO drawAwardStartDTO) {
        String awardId = drawAwardStartDTO.getAwardId();
        Date startTime = drawAwardStartDTO.getStartTime();

        // 状态修改加锁
        String lockKey = String.format(RedisKeyConstant.AWARD_CHANGE_STATUS, awardId);
        AwardAwardDO awardAwardDO;
        redisService.lock(lockKey);
        try {
            // 启动抽奖奖励
            awardAwardDO = awardAwardDao.startDrawAward(awardId, startTime);
        } finally {
            redisService.unlock(lockKey);
        }
        if (Validator.isNull(awardAwardDO)) {
            if (log.isInfoEnabled()) {
                log.info("[Award/RabbitMQ] startDrawAward task [{}]", 0);
            }
            return false;
        }
        // 对于有数量限制的情况，使用redis做奖池初始化
        // 奖池存放奖项列表下标,不中奖为-1
        if (Validator.isNotNull(awardAwardDO.getBasic().getTotalCount())) {
            List<String> pool = new ArrayList<>();
            for (int i = 0; i < awardAwardDO.getAwards().size(); i++) {
                for (int j = 0; j < awardAwardDO.getAwards().get(i).getNum(); j++) {
                    pool.add(String.valueOf(i));
                }
            }
            // 添加不中奖
            int len = awardAwardDO.getBasic().getTotalCount() - pool.size();
            for (int i = 0; i < len; i++) {
                pool.add(Constants.MINUS_ONE_STRING);
            }
            // 随机排序
            Collections.shuffle(pool);
            // 存入redis
            redisService.lLeftPushAll(String.format(RedisKeyConstant.AWARD_POOL, awardId), pool);
            // 兑奖码标志设定 False
            awardWinDao.updateUsedByAwardId(awardId, Boolean.FALSE);
        }
        if (log.isInfoEnabled()) {
            log.info("[Award/RabbitMQ] startDrawAward task [{}]", 1);
        }
        return true;
    }

    /**
     * 结束抽奖奖励
     *
     * @param drawAwardStopDTO 消息参数
     * @return 处理结果 true: 成功 false: 失败
     */
    @Override
    public boolean stopDrawAward(DrawAwardStopDTO drawAwardStopDTO) {
        String awardId = drawAwardStopDTO.getAwardId();
        Date stopTime = drawAwardStopDTO.getStopTime();
        // 状态修改加锁
        String lockKey = String.format(RedisKeyConstant.AWARD_CHANGE_STATUS, awardId);
        AwardAwardDO awardAwardDO;
        redisService.lock(lockKey);
        try {
            // 结束抽奖奖励
            awardAwardDO = awardAwardDao.stopDrawAward(awardId, stopTime);
        } finally {
            redisService.unlock(lockKey);
        }

        if (Validator.isNull(awardAwardDO)) {
            if (log.isInfoEnabled()) {
                log.info("[Award/RabbitMQ] stopDrawAward task [{}]", 0);
            }
            return false;
        }
        // 对于有数量限制的情况，使用redis存储奖池后需要清理奖池
        redisService.del(String.format(RedisKeyConstant.AWARD_POOL, awardId));
        if (log.isInfoEnabled()) {
            log.info("[Award/RabbitMQ] stopDrawAward task [{}]", 1);
        }
        return true;
    }

    /**
     * 启动微信红包奖励
     *
     * @param redPacketAwardStartDTO 消息参数
     * @return 处理结果 true: 成功 false: 失败
     */
    @Override
    public boolean startRedPacketAward(RedPacketAwardStartDTO redPacketAwardStartDTO) {
        String awardId = redPacketAwardStartDTO.getAwardId();
        Date startTime = redPacketAwardStartDTO.getStartTime();
        // 状态修改加锁
        String lockKey = String.format(RedisKeyConstant.AWARD_CHANGE_STATUS, awardId);
        AwardAwardDO awardAwardDO;
        redisService.lock(lockKey);
        try {
            // 启动微信红包奖励
            awardAwardDO = awardAwardDao.startBonusAward(awardId, startTime);
        } finally {
            redisService.unlock(lockKey);
        }

        if (Validator.isNull(awardAwardDO)) {
            if (log.isInfoEnabled()) {
                log.info("[Award/RabbitMQ] startRedPacketAward task [{}]", 0);
            }
            return false;
        }
        // 概率红包使用预计参与人数进行redis奖池初始化
        List<String> pool = new ArrayList<>();
        // 预计参与人数
        long forecastCount = awardAwardDO.getBasic().getProbability();
        // 红包个数
        Integer redPacketCount = awardAwardDO.getBasic().getTotalCount();
        if (forecastCount > Constants.ZERO) {
            // 添加抽中红包 "1"
            for (int i = 0; i < redPacketCount; i++) {
                pool.add(Constants.ONE_STRING);
            }
            // 添加不抽中红包 "0"
            long len = forecastCount - redPacketCount;
            for (int i = 0; i < len; i++) {
                pool.add(Constants.ZERO_STRING);
            }
            // 随机排序
            Collections.shuffle(pool);
            // 存入redis
            redisService.lLeftPushAll(String.format(RedisKeyConstant.AWARD_POOL, awardId), pool);
        }
        if (log.isInfoEnabled()) {
            log.info("[Award/RabbitMQ] startRedPacketAward task [{}]", 1);
        }
        return true;
    }

    /**
     * 结束微信红包奖励
     *
     * @param redPacketAwardStopDTO 消息参数
     * @return 处理结果 true: 成功 false: 失败
     */
    @Override
    public boolean stopRedPacketAward(RedPacketAwardStopDTO redPacketAwardStopDTO) {
        String awardId = redPacketAwardStopDTO.getAwardId();
        Date stopTime = redPacketAwardStopDTO.getStopTime();
        ChangeActivityStatusBodyDTO bodyDTO = redPacketAwardStopDTO.getBodyDTO();

        // 状态修改加锁
        String lockKey = String.format(RedisKeyConstant.AWARD_CHANGE_STATUS, awardId);
        AwardAwardDO awardAwardDO;
        redisService.lock(lockKey);
        try {
            // 结束微信红包奖励
            awardAwardDO = awardAwardDao.stopBonusAward(awardId, stopTime);
        } finally {
            redisService.unlock(lockKey);
        }

        if (Validator.isNull(awardAwardDO)) {
            if (log.isInfoEnabled()) {
                log.info("[Award/RabbitMQ] stopRedPacketAward task [{}]", 0);
            }
            return false;
        }
        // 概率红包，使用redis存储奖池后需要清理奖池
        redisService.del(String.format(RedisKeyConstant.AWARD_POOL, awardId));
        // 调用钱包中心 结束活动
        boolean changeActivityStatus = activityGrpcService.changeActivityStatus(awardAwardDO.getActivityId(), AwardStatusEnum.FINISH.getIndex(),
                awardAwardDO.getStatus(), bodyDTO);
        AwardAwardDO update = new AwardAwardDO();
        update.setSettlement(changeActivityStatus ? AwardSettlementEnum.SUCCESS.getIndex() : AwardSettlementEnum.FAILED.getIndex());
        awardAwardDao.updateByAwardId(awardId, update);
        if (log.isInfoEnabled()) {
            log.info("[Award/RabbitMQ] stopRedPacketAward task [{}]", 1);
        }
        return true;
    }

    /**
     * 删除项目,清算红包
     *
     * @param projectDeleteDTO 消息参数
     * @return 处理结果 true: 成功 false: 失败
     */
    @Override
    public boolean deleteProject(ProjectDeleteDTO projectDeleteDTO) {
        String projectId = projectDeleteDTO.getId();
        // 删除项目下奖励数量缓存
        String key = String.format(RedisKeyConstant.AWARD_COUNT_PROJECT, projectDeleteDTO.getOrgId(), projectDeleteDTO.getId());
        redisService.del(key);
        List<Integer> awardStatusList = new ArrayList<>();
        awardStatusList.add(AwardStatusEnum.INACTIVE.getIndex());
        awardStatusList.add(AwardStatusEnum.ACTIVE.getIndex());
        awardStatusList.add(AwardStatusEnum.PAUSE.getIndex());
        List<AwardAwardDO> awards = awardAwardDao.listAwardAwardByQdesIdAndStatus(projectDeleteDTO.getOrgId(), projectId, awardStatusList);
        if (CollectionUtil.isEmpty(awards)) {
            return false;
        }
        List<String> awardIds = new ArrayList<>();
        for (AwardAwardDO award : awards) {
            awardIds.add(award.getId());
            AwardAwardService awardAwardService = awardDispatcher.getAwardService(award.getTType());
            if (awardAwardService == null) {
                if (log.isErrorEnabled()) {
                    log.error("[Award/RabbitMQ] 删除项目,找不到对应的奖励实现类;awardId: {}, projectId: {}", award.getId(), projectId);
                }
                continue;
            }
            ServiceResult<String> result = awardAwardService.beforeFinishAward(award.getId());
            if (!result.isSuccess()) {
                if (log.isErrorEnabled()) {
                    log.error("[Award/RabbitMQ] 结束奖励前置操作失败: {}, awardId: {}", result.getMsg(), award.getId());
                }
            }
        }
        // 批量结束奖励
        awardAwardDao.batchFinishAwardByIds(awardIds);
        return true;
    }

    /**
     * 微信红包发送中状态再次查询钱包，更新状态
     *
     * @param redPacketAwardSendingDTO 消息参数
     * @return
     */
    @Override
    public boolean sendingRedPacketAward(RedPacketAwardSendingDTO redPacketAwardSendingDTO) {
        String awardId = redPacketAwardSendingDTO.getAwardId();
        String activityId = redPacketAwardSendingDTO.getActivityId();
        String orderId = redPacketAwardSendingDTO.getOrderId();
        if (StringUtils.isBlank(awardId)) {
            if (log.isErrorEnabled()) {
                log.error("[Award/RabbitMQ] sendingRedPacketAward blankAwardId:{}", JSON.toJSONString(redPacketAwardSendingDTO));
            }
            return false;
        }
        GetLuckyMoneyStatusRequest request = GetLuckyMoneyStatusRequest.newBuilder().setId(activityId)
                .setOrderId(orderId).build();
        GetLuckyMoneyStatusResponse response = activityGrpcService.getLuckyMoneyStatus(request);

        if (response.getStatus().getCodeValue() != Code.OK_VALUE) {
            if (log.isErrorEnabled()) {
                log.error("[Award/RabbitMQ] sendingRedPacketAward GetLuckyMoneyStatusResponse Fail:{}", JSON.toJSONString(redPacketAwardSendingDTO));
            }
            return false;
        }

        LuckyMoneyInfo luckyMoneyInfo = response.getLuckyMoney();
        if (luckyMoneyInfo != null && luckyMoneyInfo.getStatus() != null && luckyMoneyInfo.getStatus().getNumber() != RedPacketStatusEnum.SENDING.getIndex()) {
            awardHistoryDao.updateWinInfoByAwardIdAndOrderId(awardId, orderId, luckyMoneyInfo.getAmount(), luckyMoneyInfo.getStatus().getNumber());

            if (luckyMoneyInfo.getStatus().getNumber() == RedPacketStatusEnum.SENT.getIndex()) {
                drawCommonService.updateAwardAndSendNotification(awardId);
                awardRedPacketStatsDao.addCountAndAmountByAwardId(awardId, Constants.INT1, luckyMoneyInfo.getAmount());
            }
            return true;
        }

        return false;
    }

    @Override
    public void startAward(AwardStartDTO awardStartDTO) {
        if (log.isInfoEnabled()) {
            log.info("[award/RabbitMq] startAward :{}", JSON.toJSONString(awardStartDTO));
        }
        String awardId = awardStartDTO.getAwardId();
        Date startTime = awardStartDTO.getStartTime();
        // 状态修改加锁
        String lockKey = String.format(RedisKeyConstant.AWARD_CHANGE_STATUS, awardId);
        redisService.lock(lockKey);
        try {
            // 开始奖励
            awardAwardDao.startAward(awardId, startTime);
        } finally {
            redisService.unlock(lockKey);
        }

    }

    @Override
    public void stopAward(AwardStopDTO awardStopDTO) {
        if (log.isInfoEnabled()) {
            log.info("[award/RabbitMq] stopAward :{}", JSON.toJSONString(awardStopDTO));
        }
        String awardId = awardStopDTO.getAwardId();
        Date stopTime = awardStopDTO.getStopTime();
        // 状态修改加锁
        String lockKey = String.format(RedisKeyConstant.AWARD_CHANGE_STATUS, awardId);
        redisService.lock(lockKey);
        try {
            // 结束奖励
            awardAwardDao.stopAward(awardId, stopTime);

            AwardAwardDO award = awardAwardDao.findById(awardId);
            //如果结束了，那么删除积分奖励redis中保存的积分数量
            if (award != null && award.getBandPoint() != null && award.getBandPoint().getTotal() != null) {
                redisService.del(String.format(RedisKeyConstant.AWARD_POINT_WAIT_COUNT, awardId));
            }

        } finally {
            redisService.unlock(lockKey);
        }
    }

    /*@Override
    public void sendDrawAwardSms(DrawAwardSendSmsDTO smsDTO) {
        String smsContent = parseSmsContent(smsDTO);
        SendSmsRequest.Builder request = SendSmsRequest.newBuilder();
        request.setOrgId(smsDTO.getOrgId()).setProjectId(smsDTO.getProjectId()).setName(smsDTO.getAwardName()).setPhone(smsDTO.getPhone()).setContent(smsContent).setTypeValue(SmsRecordTypeEnum.SmsRecordType.AWARD_VALUE);
        SendSmsResponse sendSmsResponse = smsGrpcService.sendSms(request.build());
        if (Code.OK_VALUE == sendSmsResponse.getStatus().getCodeValue()) {
            if (log.isInfoEnabled()) {
                log.info("[award] 手机号:{}, 发送中奖短信通知:{};awardId={}, orgId={}, projectId={}",smsDTO.getPhone(), smsContent, smsDTO.getAwardId(), smsDTO.getOrgId(), smsDTO.getProjectId());
            }
        } else {
            log.error("[award] 手机号:{}, awardId={}, orgId={}, projectId={}, 发送中奖通知短信失败:{}", smsDTO.getPhone(), smsDTO.getAwardId(), smsDTO.getOrgId(), smsDTO.getProjectId(), sendSmsResponse.getStatus().getMessage());
        }
    }*/

    @Override
    public void sendDrawAwardSms(DrawAwardSendSmsDTO smsDTO) {
        String smsContent = parseSmsContent(smsDTO);
        smsService.sendSms(smsDTO.getPhone(), smsContent, null);
    }

    /**
     * 解析短信内容
     *
     * @param smsDTO 中奖短信通知数据
     * @return 短信内容
     */
    private String parseSmsContent(DrawAwardSendSmsDTO smsDTO) {
        String smsContent = smsDTO.getSmsContent();
        Matcher matcher = DrawUtil.SMS_PATTERN.matcher(smsContent);
        // 问卷结构数据id
        String qStructId = BLANK;
        while (matcher.find()) {
            String group = matcher.group();
            if (group.contains(SMS_TEMPLATE_AWARD_AWARD_LEVEL)) {
                smsContent = smsContent.replace(group, Objects.isNull(smsDTO.getLevel()) ? BLANK :
                        (Objects.isNull(smsDTO.getLevelStr()) ? AWARD_LEVELS[smsDTO.getLevel()] : smsDTO.getLevelStr()));
            } else if (group.contains(SMS_TEMPLATE_AWARD_AWARD_NAME)) {
                smsContent = smsContent.replace(group, Objects.isNull(smsDTO.getName()) ? BLANK : smsDTO.getName());
            } else if (group.contains(SMS_TEMPLATE_AWARD_CODE)) {
                smsContent = smsContent.replace(group, Objects.isNull(smsDTO.getCode()) ? BLANK : smsDTO.getCode());
            } else if (group.contains(SMS_TEMPLATE_PROJECT_NAME)) {
                String projectName = BLANK;
                ProjectResponse projectResponse = qdesGrpcService.getProject(GetProjectRequest.newBuilder().setId(smsDTO.getProjectId()).build());
                if (Base.Code.OK_VALUE != projectResponse.getStatus().getCodeValue()) {
                    log.error("[award] sms getProject,获取项目信息失败;awardId={}, projectId={}; ErrorMsg: {}", smsDTO.getAwardId(), smsDTO.getProjectId(), projectResponse.getStatus().getMessage());
                } else {
                    try {
                        projectName = StringUtils.isBlank(projectResponse.getProject().getTitle()) ? BLANK : projectResponse.getProject().getTitle();
                        if (projectName.length() > SMS_TEMPLATE_PROJECT_NAME_MAX_LENGTH) {
                            projectName = projectName.substring(0, SMS_TEMPLATE_PROJECT_NAME_MAX_LENGTH);
                        }
                        qStructId = projectResponse.getProject().getStructId();
                    } catch (Exception e) {
                        log.error("[award] sms 获取项信息失败, awardId={}, projectId={}: ", smsDTO.getAwardId(), smsDTO.getProjectId(), e);
                    }
                }
                smsContent = smsContent.replace(group, projectName);
            } else if (group.contains(SMS_TEMPLATE_QDES_NAME)) {
                String qdesName = qdesGrpcService.getQdesName(smsDTO.getProjectId(), qStructId);
                if (qdesName.length() > SMS_TEMPLATE_QDES_NAME_MAX_LENGTH) {
                    qdesName = qdesName.substring(0, SMS_TEMPLATE_QDES_NAME_MAX_LENGTH);
                }
                smsContent = smsContent.replace(group, qdesName);
            } else if (group.contains(SMS_TEMPLATE_SYSTEM_NAME)) {
                String systemName = userGrpcService.getSystemName(smsDTO.getOrgId());
                if (systemName.length() > SMS_TEMPLATE_SYSTEM_NAME_MAX_LENGTH) {
                    systemName = systemName.substring(0, SMS_TEMPLATE_SYSTEM_NAME_MAX_LENGTH);
                }
                smsContent = smsContent.replace(group, StringUtils.isBlank(systemName) ? SMS_TEMPLATE_DEFAULT_SYSTEM_NAME : systemName);
            }
        }
        return smsContent;
    }
}
